package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.AdChannelService;
import com.heima.admin.service.WmNewsAutoScanService;
import com.heima.apis.article.IArticleFeign;
import com.heima.apis.wemedia.IWemediaFeign;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.admin.pojos.AdSensitive;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Transactional
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private IWemediaFeign wemediaFeign;


    @Override
    public void autoScanWmNewsById(Integer id) {
        //第一部分：准入校验
        //1.1 判断参数
        if(id==null || id==0){
            log.info("[文章自动审核] 参数非法，文章ID：{}",id);
            return;
        }

        //1.2 根据ID调用feign查询自媒体文章判断是否存在
        WmNews wmNews = wemediaFeign.findOneWmNews(id);
        if(wmNews==null){
            log.info("[文章自动审核] 自媒体文章不存在，文章ID：{}",id);
            return;
        }


        //第二部分：处理曾经审核通过未发布的数据
        //2.1 人工审核通过（4）&时间允许发布的文章
        if(wmNews.getStatus().equals(WmNews.Status.ADMIN_SUCCESS.getCode()) && wmNews.getPublishTime().getTime() < System.currentTimeMillis()){
            //创建APP文章并设置文章状态为发布（9）
            saveApArticle(wmNews);
            log.info("[文章自动审核] 人工审核通过待发布的文章，已更新为发布状态，文章ID：{}",id);
            return;
        }

        //2.2 自动审核通过（8）&时间允许发布的文章
        if(wmNews.getStatus().equals(WmNews.Status.SUCCESS.getCode()) && wmNews.getPublishTime().getTime() < System.currentTimeMillis()){
            //创建APP文章并设置文章状态为发布（9）
            saveApArticle(wmNews);
            log.info("[文章自动审核] 自动审核通过待发布的文章，已更新为发布状态，文章ID：{}",id);
            return;
        }

        //只有状态为待自动审核（1）的文章才能进行自动审核
        if(wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())){
            //第三部分：三阶段审核
            //3.1 抽取所有文章中的文本和图片，文本来源：标题+内容文本， 图片来源：封面图片+内容图片
            Map result = extractTextAndImage(wmNews);

            //3.2 第一阶段审核：自管理敏感词审核
            boolean flag = scanSensitives(wmNews, (String)result.get("text"));
            if(flag){
                log.info("[文章自动审核] 第一阶段审核-自管理敏感词审核命中敏感词，审核失败，文章ID{}",id);
                return;
            }

            //3.3 第二阶段审核：阿里云文本审核
            flag = scanText(wmNews,  (String)result.get("text"));
            if(flag){
                log.info("[文章自动审核] 第二阶段审核-阿里云文本审核出现违规或建议审核，文章ID{}",id);
                return;
            }

            //3.4 第三阶段审核：阿里云图片审核
            flag = scanImage(wmNews, (List<String>)result.get("imageList"));
            if(flag){
                log.info("[文章自动审核] 第三阶段审核-阿里云图片审核出现违规或建议审核，文章ID{}",id);
                return;
            }

            //第四部分：判断发布时间&发布

            //4.1 如果发布时间大于系统当前时间，不允许发布，只能设置状态为自动审核通过（8）
            if(wmNews.getPublishTime().getTime()> System.currentTimeMillis()){
                log.info("[文章自动审核] 审核通过但时间不允许发布，文章ID{}",id);
                updateWmNews(wmNews,WmNews.Status.SUCCESS.getCode(),"审核通过但时间不允许发布");
                return;
            }

            //4.2 如果发布时间小于等于系统当前时间，可以立即创建APP文章并设置状态为已发布（9）
            saveApArticle(wmNews);
        }
    }

    @Autowired
    private GreenImageScan greenImageScan;

    //阿里云图片审核
    private boolean scanImage(WmNews wmNews, List<String> imageList) {
        boolean flag = false; //为命中违规内容
        if(imageList.size()>0){
            //由于封面图片和内容图片有可能重复，所以要去重
            imageList = imageList.stream().distinct().collect(Collectors.toList());
            try {
                Map<String,String> map = greenImageScan.imageScan(imageList);
                String sug = map.get("suggestion");
                if(sug.equals("block")){ //内容违规，审核失败，设置状态为审核失败状态（2）
                    flag = true;
                    updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"阿里云图片审核失败");
                } else if(sug.equals("review")){//建议人工审核，设置审核状态为待人工审核（3）
                    flag = true;
                    updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云图片建议人工审核");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    @Autowired
    private GreenTextScan greenTextScan;

    //阿里云文本审核
    private boolean scanText(WmNews wmNews, String text) {
        boolean flag = false; //未命中违规内容
        if(StringUtils.isNotBlank(text)){
            try {
                Map<String,String> map = greenTextScan.greeTextScan(text);
                String sug = map.get("suggestion");
                if(sug.equals("block")){ //内容违规，审核失败，设置状态为审核失败状态（2）
                    flag = true;
                    updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"阿里云文本审核失败");
                } else if(sug.equals("review")){//建议人工审核，设置审核状态为待人工审核（3）
                    flag = true;
                    updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云文本建议人工审核");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    @Autowired
    private AdSensitiveMapper adSensitiveMapper;

    //自管理敏感词审核(DFA算法审核)
    private boolean scanSensitives(WmNews wmNews, String text) {

        boolean flag = false;//未命中

        if(StringUtils.isNotBlank(text)){

            //查询到所有敏感词
            List<AdSensitive> adSensitives = adSensitiveMapper.selectList(Wrappers.emptyWrapper());

            //获取所有敏感词文本列表
            List<String> adSensitiveList = adSensitives.stream().map(AdSensitive::getSensitives).collect(Collectors.toList());

            //初始化DFA词库
            SensitiveWordUtil.initMap(adSensitiveList);

            //将文本内容拿到DFA词库进行匹配
            Map<String, Integer> map = SensitiveWordUtil.matchWords(text);

            //根据MAP结果判断是否命中敏感词
            if(map.size()>0){
                flag = true; //已命中，设置审核失败状态（2）
                updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),"自管理敏感词审核失败");
            }
        }

        return flag;
    }




    @Value("${file.oss.web-site}")
    private String webSite;

    //抽取所有文章中的文本和图片，文本来源：标题+内容文本， 图片来源：封面图片+内容图片
    private Map extractTextAndImage(WmNews wmNews) {
        StringBuffer text = new StringBuffer();
        text.append(wmNews.getTitle()); //拼接文本的第一个来源：文章标题

        List<String> imageList = new ArrayList<>(); //带域名的图片地址列表
        if(StringUtils.isNotBlank(wmNews.getContent())){
            List<Map> mapList = JSON.parseArray(wmNews.getContent(), Map.class);
            if(mapList!=null && mapList.size()>0){
                for (Map<String,String> map : mapList) {
                    String type = map.get("type");
                    if(type.equals("text")){
                        String textVal = map.get("value");
                        text.append(textVal);//拼接文本的第二个来源：内容文本
                    }

                    if(type.equals("image")){
                        String imageUrl = map.get("value");
                        if(!imageUrl.startsWith(webSite)){
                            imageUrl = webSite +  imageUrl;//拼接上OSS域名
                        }
                        imageList.add(imageUrl);//添加图片的第一个来源：内容图片
                    }
                }
            }
        }

        if(StringUtils.isNotBlank(wmNews.getImages())){
            String coverImages = wmNews.getImages();
            String[] coverImagesArr = coverImages.split(",");
            for (String imageUrl : coverImagesArr) {
                if(!imageUrl.startsWith(webSite)){
                    imageUrl = webSite +  imageUrl;//拼接上OSS域名
                }
                imageList.add(imageUrl);//添加图片的第二个来源：封面图片
            }
        }


        Map map = new HashMap();
        map.put("text", text.toString()); //全部文本
        map.put("imageList", imageList); //全部带域名的图片地址列表

        return map;
    }

    @Autowired
    private IArticleFeign articleFeign;

    @Autowired
    private AdChannelService adChannelService;

    //公共方法：保存APP文章 &  设置状态为9
    private void saveApArticle(WmNews wmNews) {
        //1.构建ArticleDto
        ArticleDto articleDto = new ArticleDto();
        articleDto.setId(wmNews.getArticleId()); //app文章ID
        articleDto.setTitle(wmNews.getTitle());//文章标题
        articleDto.setContent(wmNews.getContent());//文章内容
        articleDto.setLayout(wmNews.getType()); //文章布局
        articleDto.setImages(wmNews.getImages());//文章封面
        articleDto.setCreatedTime(wmNews.getCreatedTime());//文章创建时间
        articleDto.setPublishTime(wmNews.getPublishTime());//定时发布时间
        //调用feign查询作者
        ApAuthor apAuthor = articleFeign.findByWmUserId(wmNews.getUserId());
        if(apAuthor!=null){
            articleDto.setAuthorId(apAuthor.getId().longValue());//作者ID
            articleDto.setAuthorName(apAuthor.getName());//作者名
        }

        //查询频道
        AdChannel adChannel = adChannelService.getById(wmNews.getChannelId());
        if(adChannel!=null){
            articleDto.setChannelId(adChannel.getId()); //频道ID
            articleDto.setChannelName(adChannel.getName()); //频道名
        }


        //2.调用feign接口保存ApArticle
        ResponseResult responseResult = articleFeign.saveApArticle(articleDto);
        if(responseResult.getCode()!=200){
            log.info("[文章自动审核] feign保存APP文章出错，文章ID:{}", wmNews.getId());
            throw new RuntimeException("保存APP文章出错，文章ID：" + wmNews.getId());
        }

        //3.获取feign接口响应结果里的ApArticle的ID
        Long appArticleId = Long.valueOf(responseResult.getData() + "");


        //4.将APP文章ID设置到wmNews中并更新状态为已发布（9）
        wmNews.setArticleId(appArticleId); //app文章ID
        updateWmNews(wmNews, WmNews.Status.PUBLISHED.getCode(), "文章审核通过已发布");
    }

    //公共方法：更新文章状态及描述信息
    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status); //文章状态
        wmNews.setReason(reason); // 描述信息
        //调用feign更新自媒体文章
        wemediaFeign.updateWmNews(wmNews);
    }
}
